<?php
/**
 * 
 * @author nrnwest@gmail.com
 *
 */
class Arm_Translate
{
    /**
     * Arm_Translate_Sql_Pdo_Mysql
     * @var Arm_Translate_Sql_Pdo_Mysql
     */
    private $_sql;

    /**
     * Zend_Translate
     * @var Zend_Translate
     */
    private $_zendTranslate = null;

    /**
     * Текущий язык
     * @var string
     */
    private $_language = null;

    /**
     * Язык по умолчанию
     * @var string
     */
    private $_languageDefault = null;

    /**
     * Зарегистированные языки в системе, включая язык по умолчанию
     * array('ru'=>'ru',...)
     * @var array
     */
    private $_languagesRegister = array();

    /**
     * каким методом определяется текущий язык пользователя.
     *
     * @var string
     */
    private $_method = null;

    /**
     * Arm_Translate
     *
     * @var Arm_Translate
     */
    private static $_instance = null;

    /**
     * Если язык не будет зарегистрирован в системе,
     * будет выведенна ошибка. и данном значение будет названия
     * ошибочного языка.
     * @var bool|string
     */
    private $_laguageError = false;
     
    private function __construct()
    {
        $this->_sql = Arm_Db::getSqlObject('Arm_Translate_Sql', Arm_Db::getAdapter());
        $config = Arm_Core::getConfigApplication();
        $this->_method = $config->language->method;
        $this->_setSystemLanguages();
        $this->_setLanguage();
        $this->_setTranslate();
    }

   /**
    * Установка в систему языков.
    */
   private function _setSystemLanguages()
   {
      if(Arm_Core::getEnvironment() === 'install') {
          $langs = $this->_getLanguagesInstall();
      } else {
      $langs = $this->_sql->getLanguages();
      }
      foreach ($langs as $k=>$v) {
          if(1 === (int)$v['default']) {
              $this->_languageDefault = $v['name'];
          }
          $this->_languagesRegister[$v['name']]          = array();
          $this->_languagesRegister[$v['name']]['title'] = $v['title'];
          $this->_languagesRegister[$v['name']]['id']    = $v['id'];
      }
   }
   
   /**
    * Получения языков во время инстеляции.
    */
   private function _getLanguagesInstall()
   {
       $config = Arm_Core::getConfigApplication();
       $install =   $config->toArray();
       return $install['languages'];
   }
   
   /**
    * Arm_Translate_Sql_Pdo_Mysql
    * 
    * @return Arm_Translate_Sql_Pdo_Mysql
    */
   public function getSql()
   {
       return $this->_sql;
   }
    
    /**
     * Вернет id языка по умолчанию
     * 
     * @return int
     */
    public function getIdLangDefault()
    {
       return $this->_languagesRegister[$this->_languageDefault]['id'];
    }
    
    /**
     * Вернет описания языка
     * 
     * @return string
     */
    public function getTitleLangDefault()
    {
       return $this->_languagesRegister[$this->_languageDefault]['title'];
    }
    
    /**
     * Вернет все яызки в системе
     * 
     * @return array
     */
    public function getLanguages()
    {
       return $this->_languagesRegister;
    }
    
    /**
     * Вернет id текущего  языка или указаного в $lang
     * 
     * @param string|null $lang язык для которого нужно получить описание 
     * @return int
     */
    public function getIdLang($lang = null)
    {
    if($lang === null) {
          $lang = $this->_language;
      }
      $this->_isValidLang($lang);
      return $this->_languagesRegister[$lang]['id'];
    }
    
    /**
     * Проверим зарегистрован ли язык в системе
     * @throw Arm_Translate_Exception если язык не зарегистрирован в системе
     * @param string $lang
     */
    private function _isValidLang($lang)
    {
        if(false === array_key_exists($lang, $this->_languagesRegister)) {
            throw new Arm_Translate_Exception(Arm_Translate::_('Язык "%s" не зарегистрирован в системе', $lang));
        }
        return;
    }
    
    /**
     * Вернет описания текущего или укзано в $lang
     * 
     * @param string|null $lang язык для которого нужно получить описание 
     * @return string
     */
    public function getTitleLang($lang = null)
    {
      if($lang === null) {
          $lang = $this->_language;
      }
      $this->_isValidLang($lang);
      return $this->_languagesRegister[$lang]['title'];
    }

    /**
     * Arm_Translate
     *
     * @return Arm_Translate
     */
    public static function getInstance()
    {
        if(self::$_instance === null) {
            self::$_instance = new Arm_Translate();
        }
        return self::$_instance;
    }

    /**
     * Установка адаптеров
     *
     * @return void
     */
    protected function _setTranslate ()
    {
        $pathLibrary = Arm_Core::getPathApplication() . 'translate/library/'.$this->getLanguage().'.mo';
        if(is_file($pathLibrary) === false and $this->isLangDefault() === false) {
            $pathLibrary = Arm_Core::getPathApplication() . 'translate/library/'.$this->_languageDefault.'.mo';
            $this->_zendTranslate = new Zend_Translate('gettext',  $pathLibrary, $this->_languageDefault,  array('disableNotices' => true));
        } else {
            $this->_zendTranslate = new Zend_Translate('gettext',  $pathLibrary, $this->getLanguage(),  array('disableNotices' => true));
        }

        // проверка для директории layout

        $pathLayout = Arm_Core::getPathApplication() .  'translate/layouts/'.$this->getLanguage().'.mo';
        if(is_file($pathLayout) === false and $this->isLangDefault() === false) {
            $pathLayout =   Arm_Core::getPathApplication() .  'translate/layouts/'.$this->_languageDefault.'.mo';
            $this->getAdapter()->addTranslation($pathLayout, $this->_languageDefault);
        } else {
            $this->getAdapter()->addTranslation($pathLayout, $this->getLanguage());
        }
         // локоль выставляем по текущему языку
        $this->getAdapter()->setLocale($this->getLanguage());
    }


    /**
     * Добавления много язычного интерфейса модуля.
     * @param string $module директория модуля.
     */
    public function addTranslateModule($module)
    {
        $path = Arm_Core::getPathModule($module) . 'translate/' . $this->getLanguage() . '.mo';
        if(is_file($path) === false and $this->isLangDefault() === false) {
            $path = Arm_Core::getPathModule($module)  . 'translate/' . $this->_languageDefault . '.mo';
            $this->getAdapter()->addTranslation($path, $this->_languageDefault);
        } else {
            $this->getAdapter()->addTranslation($path, $this->getLanguage());
        }
        // локоль выставляем по текущему языку
        $this->getAdapter()->setLocale($this->getLanguage());
    }

     

    /**
     * @todo дорабатываем этот метод.
     * Определения языка интерфейса.
     */
    private function _setLanguage ()
    {
        if(Arm_Core::isCliRequest()) {
            $this->_language = $this->_languageDefault;
            return;
        }

        $class = 'Arm_Translate_Method_' . ucfirst(strtolower(trim($this->_method)));
        if ( false === class_exists($class, true)) {
            throw new Arm_Exception('Not Class:' . $class);
        }
        $method = new $class($this->_languageDefault);
        $this->_language = $method->getLang();
         
        // нужна проверка зарегистрирован язык в системе или нет.
        // если язык не зарегистрирован, выставляем язык по умолчанию.
        // и выставляем флаг что нужно бросить исключение. с кодом 404
        if(array_key_exists($this->_language, $this->_languagesRegister) === false) {
            $this->_laguageError = $this->_language;
            $this->_language = $this->_languageDefault;
        }

    }

    /**
     * Вернет текущий язык двух символьную строку 
     * 
     * @return string 
     */
    public function getLanguage()
    {
        return $this->_language;
    }

    /**
     * Вернет true если текущий язык являться и дефолтовым языком в системе
     *
     *
     * @return bool
     */
    public function isLangDefault()
    {
        if($this->_language === $this->_languageDefault) {
            return true;
        }
        return false;
    }

    /**
     * Вернет язык по умолчанию.
     *
     * @return string
     */
    public function getLanguageDefault()
    {
        return $this->_languageDefault;
    }

    /**
     * Zend_Translate_Adapter
     *
     * @return Zend_Translate_Adapter
     */
    public function getAdapter()
    {
        return $this->_zendTranslate->getAdapter();
    }
    
    /**
     * Zend_Translate
     * 
     * @return Zend_Translate
     */
    public function getZendTraslate()
    {
        return $this->_zendTranslate;
    }

    /**
     * Вернет либо false либо названия языка который указал пользователь
     * но его нету в системе.
     *
     * @return false|string
     */
    public function getErrorLang()
    {
        return $this->_laguageError;
    }

    /**
     * Перевод сообщений Диначмические данные с $data не перводяться они будут добавлены в строку
     * после перевода.!
     * @param string $str динамические данные легко добавить в виде строки используя %s функция аналогична sprintf
     * @param array|string $data динамические значения которые нужно добавить в $str с $data
     * @param $lang
     */
    public static function _($str, $data=array(), $lang=null)
    {
        if($lang === null) {
           $lang = self::getInstance()->getLanguage();
        }
        $res = self::getInstance()->getAdapter()->_($str, $lang);
        $data = (array) $data;
        if($data === array()) {
        	return $res;
        }
        $params = array();
        $params[] = $res;
        foreach ($data as $k=>$v) {
        	$params[] = $v;
        }
        $result = call_user_func_array('sprintf', $params);
        if($result === false) {
            throw new Arm_Translate_Exception('Не верные данные при вызове метода _() вы должны передавать точное количество даных ($data) и меток %s');
        }
        return $result;
    }
}